﻿using System.Data;
using System.Linq.Expressions;
using Gateway.IRepositories;
using Gateway.SqlSugar.Splits;
using Microsoft.Data.SqlClient;
using SqlSugar;

namespace Gateway.SqlSugar;

/// <summary>
/// sql sugar 仓储
/// </summary>
public class SqlSugarRepository : IQueryRepository
{
    public SqlSugarScope Db { get; }

    public SqlSugarRepository(SqlSugarDbContext dbContext)
    {
        Db = dbContext.Scope;
    }

    private List<SugarParameter> GetParameters(object param)
    {
        if (param == null)
            return new List<SugarParameter>();
        if (param.GetType() == typeof(SugarParameters))
        {
            return ((SugarParameters)param).Get();
        }

        if (param.GetType() == typeof(SugarParameter))
        {
            return   new List<SugarParameter>(){(SugarParameter)param};
        }
        if (param.GetType() != typeof(SugarParameter))
        {
            List<SugarParameter> parameters = new List<SugarParameter>();
            var properties = param.GetType().GetProperties();
            foreach (var item in properties)
            {
                var name= item.Name;
                var value = item.GetValue(param, null);
                parameters.Add(new SugarParameter("@"+name,value));
            }

            return parameters;
        }

        return new List<SugarParameter>();
    }

    public T QueryFirstOrDefault<T>(string sql, object param = null)
    {
        return Db.Ado.SqlQuerySingle<T>(sql, param);
    }

    public async Task<T> QueryFirstOrDefaultAsync<T>(string sql, object param = null)
    {
        return await Db.Ado.SqlQuerySingleAsync<T>(sql, GetParameters(param));
    }

    public async Task<dynamic> QueryFirstOrDefaultAsync(string sql, object param = null)
    {
        return await Db.Ado.SqlQuerySingleAsync<dynamic>(sql, GetParameters(param));
    }

    public IEnumerable<T> Query<T>(string sql, object param = null, IDbTransaction transaction = null,
        bool buffered = true,
        int? commandTimeout = null, CommandType? commandType = null)
    {
        return Db.Ado.SqlQuery<T>(sql, GetParameters(param));
    }

    public async Task<IEnumerable<T>> QueryAsync<T>(string sql, object param = null, IDbTransaction transaction = null,
        int? commandTimeout = null,
        CommandType? commandType = null)
    {
        return await Db.Ado.SqlQueryAsync<T>(sql, GetParameters(param));
    }
    

    public async Task<List<T>> QueryListAsync<T>(string sql, object param = null, IDbTransaction transaction = null,
        int? commandTimeout = null,
        CommandType? commandType = null)
    {
        var data = await Db.Ado.SqlQueryAsync<T>(sql, GetParameters(param));
        return data;
    }

    public async Task<IEnumerable<dynamic>> QueryAsync(string sql, object param = null,
        IDbTransaction transaction = null, int? commandTimeout = null,
        CommandType? commandType = null)
    {
        var data = await Db.Ado.SqlQueryAsync<dynamic>(sql, GetParameters(param));

        return data;
    }

    public async Task<T> FindAsync<T>(Expression<Func<T, bool>> expression)
    {
        return await Db.Queryable<T>().Where(expression).FirstAsync();
    }

    public async Task<T> FindSplitAsync<T>(object splitId,Expression<Func<T, bool>> expression)
    {
        return await Db.Queryable<T>().MySplitTable(splitId).Where(expression).FirstAsync();
    }


    public async Task<List<T>> GetListAsync<T>(Expression<Func<T, bool>> expression)
    {
        return await Db.Queryable<T>().Where(expression).ToListAsync();
    }

    public async Task<T> FindSplitAsync<T>(Expression<Func<T, bool>> expression)
    {
        return await Db.Queryable<T>().SplitTable().Where(expression).FirstAsync();
    }
}